package com.qilu.careprogram.service.impl;

import org.springframework.web.client.RestTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.HttpEntity;
import org.springframework.http.ResponseEntity;
import org.springframework.http.HttpMethod;

import com.alibaba.fastjson.JSON;

import java.util.Map;
import java.util.HashMap;
import java.util.List;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.Calendar;
import java.util.UUID;

import com.qilu.careprogram.pojo.dto.QaQueryDTO;
import com.qilu.careprogram.pojo.dto.NurseAnswerDTO;
import com.qilu.careprogram.model.PageResult;
import com.qilu.careprogram.pojo.vo.QaVO;
import com.qilu.careprogram.pojo.dto.WxSubscribeMessageDTO;
import com.qilu.careprogram.dao.MessageAlertDAO;
import com.qilu.careprogram.pojo.entity.WxUser;
import com.qilu.careprogram.service.MessageAlertService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.qilu.careprogram.pojo.dto.DoctorAnswerLinkDTO;
import com.qilu.careprogram.pojo.dto.DoctorAnswerDTO;
import com.qilu.careprogram.pojo.vo.DoctorQuestionVO;

import java.time.LocalDateTime;
import java.util.*;

@Service
public class MessageAlertServiceImpl implements MessageAlertService {

    private static final String APPID = "wx55b30ba8f8cc2fe4";
    private static final String APPSECRET = "f4d0037141d5ddaf3439bcfdbd0d3b7d";
    // 微信接口URL（获取AccessToken、发送订阅消息）
    private static final String WX_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s";
    private static final String WX_SUBSCRIBE_MSG_URL = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=%s";

    // 缓存AccessToken（有效期7200秒，避免频繁调用接口）
    private static String accessToken;
    private static long accessTokenExpireTime; // 过期时间（毫秒数）

    @Autowired
    private MessageAlertDAO messageAlertDAO;
    // 注入RestTemplate（用于调用微信接口，需在配置类中配置Bean）
    @Autowired
    private RestTemplate restTemplate;

    /**
     * 发送微信订阅消息核心逻辑
     */
    @Override
    public String sendSubscribeMessage(WxSubscribeMessageDTO messageDTO) throws Exception {
        // 1. 校验参数（避免空指针）
        if (messageDTO == null || messageDTO.getOpenid() == null || messageDTO.getTemplateId() == null || messageDTO.getData() == null) {
            throw new RuntimeException("发送消息参数不完整（openid、templateId、data不能为空）");
        }

        // 2. 获取有效的AccessToken（优先使用缓存，过期则重新获取）
        String accessToken = getValidAccessToken();

        // 3. 转换消息内容格式（前端传{"thing1":"测试成功"} → 微信要求{"thing1":{"value":"测试成功"}}）
        Map<String, Map<String, String>> wxMsgData = new HashMap<>();
        for (Map.Entry<String, String> entry : messageDTO.getData().entrySet()) {
            Map<String, String> valueMap = new HashMap<>();
            valueMap.put("value", entry.getValue()); // 微信要求的格式：key对应模板字段，value是{"value": 内容}
            wxMsgData.put(entry.getKey(), valueMap);
        }

        // 4. 构造微信订阅消息接口的请求参数
        Map<String, Object> wxRequest = new HashMap<>();
        wxRequest.put("touser", messageDTO.getOpenid()); // 接收者openid
        wxRequest.put("template_id", messageDTO.getTemplateId()); // 订阅消息模板ID
        wxRequest.put("data", wxMsgData); // 转换后的消息内容

        // 5. 调用微信订阅消息接口（POST请求）
        String wxApiUrl = String.format(WX_SUBSCRIBE_MSG_URL, accessToken);
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON); // 设置请求格式为JSON
        HttpEntity<String> requestEntity = new HttpEntity<>(JSON.toJSONString(wxRequest), headers);

        // 发送请求并接收响应
        ResponseEntity<String> response = restTemplate.exchange(
                wxApiUrl,
                HttpMethod.POST,
                requestEntity,
                String.class
        );

        // 6. 处理微信接口响应（判断是否发送成功）
        String wxResponse = response.getBody();
        if (wxResponse == null) {
            throw new RuntimeException("微信接口返回空响应");
        }

        // 解析微信返回的errcode（0表示成功，其他为失败）
        Map<String, Object> responseMap = JSON.parseObject(wxResponse, Map.class);
        Integer errCode = (Integer) responseMap.get("errcode");
        if (errCode != null && errCode != 0) {
            String errMsg = (String) responseMap.get("errmsg");
            throw new RuntimeException("微信消息发送失败：errcode=" + errCode + ", errmsg=" + errMsg);
        }

        return wxResponse; // 返回微信接口的成功响应
    }

    /**
     * 获取有效的AccessToken（缓存+过期控制）
     */
    private String getValidAccessToken() throws Exception {
        // 检查缓存的AccessToken是否存在且未过期（过期时间提前100秒，避免临界情况）
        if (accessToken != null && System.currentTimeMillis() < accessTokenExpireTime - 100000) {
            System.out.println("使用缓存的AccessToken");
            return accessToken;
        }

        // 缓存过期，重新调用微信接口获取AccessToken
        String tokenUrl = String.format(WX_ACCESS_TOKEN_URL, APPID, APPSECRET);
        ResponseEntity<String> response = restTemplate.getForEntity(tokenUrl, String.class);
        String tokenResponse = response.getBody();

        if (tokenResponse == null) {
            throw new RuntimeException("获取AccessToken失败：微信接口返回空");
        }

        // 解析AccessToken和过期时间（微信返回expires_in为秒数，转换为毫秒）
        Map<String, Object> tokenMap = JSON.parseObject(tokenResponse, Map.class);
        accessToken = (String) tokenMap.get("access_token");
        Integer expiresIn = (Integer) tokenMap.get("expires_in");

        if (accessToken == null || expiresIn == null) {
            throw new RuntimeException("解析AccessToken失败：" + tokenResponse);
        }

        // 更新缓存和过期时间（当前时间 + 有效期毫秒数）
        accessTokenExpireTime = System.currentTimeMillis() + (expiresIn * 1000);
        System.out.println("重新获取AccessToken成功，有效期至：" + new Date(accessTokenExpireTime));

        return accessToken;
    }

    @Override
    public String getOpenid(String code, String hospitalNumber) throws Exception {
        String code2SessionUrl = String.format(
                "https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code",
                APPID,          // 你的小程序正式APPID
                APPSECRET,      // 你的小程序正式AppSecret
                code            // 前端通过 uni.login 获取的临时code
        );

        try {
            // 3. 调用微信 code2Session 接口（发送GET请求）
            // 利用已注入的 RestTemplate 发送请求，接收响应结果
            ResponseEntity<String> response = restTemplate.getForEntity(code2SessionUrl, String.class);
            String wxResponse = response.getBody();

            // 4. 校验接口响应是否为空
            if (wxResponse == null || wxResponse.trim().isEmpty()) {
                throw new RuntimeException("获取OpenID失败：微信code2Session接口返回空响应");
            }
            System.out.println("微信code2Session接口返回原始数据：" + wxResponse); // 调试日志，便于排查问题

            // 5. 解析微信返回的JSON数据（使用FastJSON）
            // 微信成功返回格式：{"openid":"o6_bmjrPTlm6_2sgVt7hMZOPfL2M","session_key":"tiihtNczf5v6AKRyjwEUhQ==","errcode":0,"errmsg":"success"}
            Map<String, Object> responseMap = JSON.parseObject(wxResponse, Map.class);

            // 6. 处理微信接口的错误（若返回errcode非0，说明调用失败）
            if (responseMap.containsKey("errcode")) {
                Integer errCode = (Integer) responseMap.get("errcode");
                String errMsg = (String) responseMap.get("errmsg");
                // 常见错误码说明：40029（code无效）、45011（code已使用）、40163（code过期）、40013（APPID错误）
                throw new RuntimeException("微信code2Session接口调用失败：errcode=" + errCode + "，errmsg=" + errMsg);
            }

            // 7. 提取真实的OpenID（微信返回的关键字段是"openid"，必须与这个键完全一致）
            String realOpenid = (String) responseMap.get("openid");
            if (realOpenid == null || realOpenid.trim().isEmpty()) {
                throw new RuntimeException("获取OpenID失败：微信接口返回的openid为空");
            }
            System.out.println("成功获取真实OpenID：" + realOpenid); // 调试日志，确认OpenID有效性

            // 8. 原有业务逻辑不变（查询或新增WxUser记录，使用真实OpenID）
            WxUser wxUser = messageAlertDAO.getWxUserByHospitalNumberAndOpenid(hospitalNumber, realOpenid);
            if (wxUser == null) {
                wxUser = new WxUser();
                wxUser.setHospitalNumber(hospitalNumber);
                wxUser.setOpenid(realOpenid); // 关键：存入真实OpenID
                wxUser.setCreateTime(LocalDateTime.now());
                wxUser.setUpdateTime(LocalDateTime.now());
                wxUser.setAlertNum(0);
                messageAlertDAO.insertWxUser(wxUser);
                System.out.println("新增WxUser记录：住院号=" + hospitalNumber + "，OpenID=" + realOpenid);
            } else {
                System.out.println("WxUser记录已存在：住院号=" + hospitalNumber + "，OpenID=" + realOpenid);
            }

            // 9. 返回真实OpenID给前端
            return realOpenid;

        } catch (Exception e) {
            // 捕获异常并补充上下文信息，便于排查
            throw new RuntimeException("获取OpenID全过程失败：" + e.getMessage(), e);
        }
    }

    @Override
    @Transactional
    public void addAuthority(String openid, String hospitalNumber) throws Exception {
        WxUser wxUser = messageAlertDAO.getWxUserByHospitalNumberAndOpenid(hospitalNumber, openid);
        if (wxUser != null) {
            wxUser.setAlertNum(wxUser.getAlertNum() + 1);
            wxUser.setUpdateTime(LocalDateTime.now());
            messageAlertDAO.updateWxUser(wxUser);
        }
    }

    @Override
    public Map<String, Object> historyQa(String hospitalNumber) throws Exception {
        List<Map<String, Object>> questionList = messageAlertDAO.getRecentQuestions(hospitalNumber);
        List<Map<String, Object>> resultList = new ArrayList<>();
        int totalCount = 0; // 总计数器，控制问题-答案对总数不超过20

        for (Map<String, Object> question : questionList) {
            Long questionId = (Long) question.get("id");
            String questionText = (String) question.get("text");

            // 获取该问题的所有答案
            List<Map<String, Object>> answers = messageAlertDAO.getAnswersByQuestionId(questionId);

            // 处理每个答案（从后往前遍历），与问题组成一对一的条目
            for (int i = answers.size() - 1; i >= 0; i--) {
                Map<String, Object> answer = answers.get(i);

                // 检查是否已达到20个限制
                if (totalCount >= 20) {
                    break;
                }

                String text = (String) answer.get("text");
                Integer source = (Integer) answer.get("source");
                String prefix = getSourcePrefix(source);
                String processedAnswer = prefix + text;

                // 每个答案单独形成一个问题-答案对
                Map<String, Object> item = new HashMap<>();
                item.put("question", questionText);
                item.put("answer", processedAnswer); // 单个答案
                resultList.add(item);

                totalCount++;
            }

            // 如果已经达到20个，停止处理后续问题
            if (totalCount >= 20) {
                break;
            }
        }

        return Collections.singletonMap("historyQa", resultList);
    }

    // 辅助方法保持不变
    private String getSourcePrefix(Integer source) {
        if (source == null) {
            return "";
        }
        switch (source) {
            case 0:
                return "该问题答案由您的主治医生进行作答：";
            case 1:
                return "该问题答案由医护人员进行作答：";
            case 2:
                return "该问题答案由AI助手生成：";
            default:
                return "";
        }
    }

    @Override
    public PageResult selectQa(QaQueryDTO queryDTO) {
        // 打印传入的查询参数，检查参数是否正确
        System.out.println("进入selectQa方法，查询参数queryDTO：" + queryDTO);

        // 计算分页起始位置
        int offset = (queryDTO.getPageNum() - 1) * queryDTO.getPageSize();
        System.out.println("计算分页offset：" + offset + "，pageNum：" + queryDTO.getPageNum() + "，pageSize：" + queryDTO.getPageSize());

        // 处理时间参数：如果存在则增加8小时（查询时用）
        Date startTime = queryDTO.getStartTime();
        Date endTime = queryDTO.getEndTime();

        if (startTime != null) {
            startTime = addHours(startTime, 8);
            System.out.println("调整后的startTime：" + startTime);
        }
        if (endTime != null) {
            endTime = addHours(endTime, 8);
            System.out.println("调整后的endTime：" + endTime);
        }

        // 查询数据
        System.out.println("开始执行selectQa查询，参数：authority=" + queryDTO.getAuthority() +
                "，hospitalNumber=" + (("全部".equals(queryDTO.getHospitalNumber()) ? null : queryDTO.getHospitalNumber())) +
                "，startTime=" + startTime + "，endTime=" + endTime +
                "，status=" + queryDTO.getStatus() + "，offset=" + offset + "，pageSize=" + queryDTO.getPageSize());

        List<QaVO> list = messageAlertDAO.selectQa(
                queryDTO.getAuthority(),
                "全部".equals(queryDTO.getHospitalNumber()) ? null : queryDTO.getHospitalNumber(),
                startTime,
                endTime,
                queryDTO.getStatus(),
                queryDTO.getQuestionMh(),
                offset,
                queryDTO.getPageSize()
        );

        // 打印查询结果数量
        System.out.println("selectQa查询返回数据量：" + (list != null ? list.size() : 0));

        // 查询总数
        System.out.println("开始执行countQa查询，参数同上");
        int total = messageAlertDAO.countQa(
                queryDTO.getAuthority(),
                "全部".equals(queryDTO.getHospitalNumber()) ? null : queryDTO.getHospitalNumber(),
                startTime,
                endTime,
                queryDTO.getStatus(),
                queryDTO.getQuestionMh()
        );
        System.out.println("countQa查询返回总数：" + total);

        // 处理处理人显示和时间调整（返回前端的时间减去8小时）
        System.out.println("开始处理处理人显示和时间调整，共" + (list != null ? list.size() : 0) + "条数据");
        if (list != null) {
            for (QaVO vo : list) {
                System.out.println("处理QaVO，id：" + vo.getId() + "，source：" + vo.getSource() + "，原始handler：" + vo.getHandler());

                // 处理处理人
                if (vo.getSource() == 0 || vo.getSource() == 2) {
                    String sourceName = messageAlertDAO.getSourceName(vo.getSource());
                    vo.setHandler(sourceName);
                    System.out.println("source为" + vo.getSource() + "，设置handler为sourceName：" + sourceName);
                } else if (vo.getSource() == 1) {
                    String username = messageAlertDAO.getUsernameById(vo.getName());
                    vo.setHandler(username);
                    System.out.println("source为1，设置handler为username：" + username + "（name参数：" + vo.getName() + "）");
                }

                // 处理时间：返回给前端的时间减去8小时
                Date createTime = vo.getCreateTime();
                if (createTime != null) {
                    Date adjustedTime = subtractHours(createTime, 8);
                    vo.setCreateTime(adjustedTime);
                    System.out.println("调整时间：原始时间=" + createTime + "，调整后时间=" + adjustedTime);
                }
            }
        }

        PageResult result = new PageResult(list, total);
        System.out.println("selectQa方法返回结果：" + result);
        return result;
    }

    // 辅助方法：为日期增加指定小时数（查询时用）
    private Date addHours(Date date, int hours) {
        if (date == null) {
            return null;
        }
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.HOUR_OF_DAY, hours);
        return calendar.getTime();
    }

    // 新增辅助方法：为日期减去指定小时数（返回前端时用）
    private Date subtractHours(Date date, int hours) {
        if (date == null) {
            return null;
        }
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.HOUR_OF_DAY, -hours); // 减去指定小时数
        return calendar.getTime();
    }


    @Override
    @Transactional
    public void nurseAnswer(NurseAnswerDTO answerDTO) {
        // 获取question_id
        Long questionId = messageAlertDAO.getQuestionIdByAnswerId(answerDTO.getId());

        // 更新question表状态
        messageAlertDAO.updateQuestionStatus(questionId);

        // 查询当前有效的答案
        Map<String, Object> activeAnswer = messageAlertDAO.getActiveAnswer(questionId);

        // 插入新答案
        if (activeAnswer == null) {
            // 没有有效答案，直接插入并设为有效
            messageAlertDAO.insertNurseAnswer(
                    questionId,
                    1, // source=1表示护士回答
                    answerDTO.getUserId(),
                    answerDTO.getAnswerText(),
                    true
            );
        } else {
            Long activeAnswerId = (Long) activeAnswer.get("id");
            Integer activeSource = (Integer) activeAnswer.get("source");

            // 插入新答案
            messageAlertDAO.insertNurseAnswer(
                    questionId,
                    1,
                    answerDTO.getUserId(),
                    answerDTO.getAnswerText(),
                    activeSource != 0
            );

            // 如果原有效答案不是GPT生成的，将其禁用
            if (activeSource != 0) {
                messageAlertDAO.updateAnswerStatus(activeAnswerId, false);
            }
        }

        // TODO: 发送微信消息通知患者
    }

    @Override
    //@Transactional
    public DoctorAnswerLinkDTO getDoctorAnswerLink(Long answerId) {
        // 获取questionId
        Long questionId = messageAlertDAO.getQuestionIdByAnswerId(answerId);
        if (questionId == null) {
            throw new RuntimeException("找不到对应的问题");
        }

        // 查找有效的token
        Map<String, Object> validToken = messageAlertDAO.getValidQuestionToken(questionId);

        // 如果没有有效的token，则创建一个新的
        if (validToken == null || validToken.isEmpty()) {
            System.out.println("creat UUID");
            String token = UUID.randomUUID().toString();
            System.out.println(questionId);
            System.out.println(token);
            System.out.println(new Date());
            int rows = messageAlertDAO.insertQuestionToken(questionId, token);
            System.out.println("插入操作影响的行数: " + rows);
            if (rows == 0) {
                throw new RuntimeException("插入question_token记录失败");
            }
            //validToken = messageAlertDAO.getValidQuestionToken(questionId);
            validToken = new HashMap<>();
            validToken.put("question_id", questionId);
            validToken.put("token", token);
            System.out.println("validToken: " + validToken);
        }

        DoctorAnswerLinkDTO result = new DoctorAnswerLinkDTO();
        System.out.println("link info" + validToken);
        result.setQuestionId((Long) validToken.get("question_id"));
        result.setToken((String) validToken.get("token"));

        return result;
    }

    @Override
    public DoctorQuestionVO getQuestionForDoctor(Long questionId, String token) {
        // 验证token
        Integer isValid = messageAlertDAO.validateToken(questionId, token);
        if (isValid == null || isValid == 0) {
            throw new RuntimeException("链接已失效，请重新申请链接");
        }

        // 获取问题信息
        Map<String, Object> questionMap = messageAlertDAO.getQuestionForDoctor(questionId);
        if (questionMap == null || questionMap.isEmpty()) {
            throw new RuntimeException("找不到对应的问题");
        }

        // 获取护士的回答
        String nurseAnswer = messageAlertDAO.getNurseAnswer(questionId);
        if (nurseAnswer == null) {
            nurseAnswer = "";
        }

        DoctorQuestionVO result = new DoctorQuestionVO();
        result.setHospitalNumber((String) questionMap.get("hospital_number"));
        result.setQuestionText((String) questionMap.get("text"));
        result.setAnswerText(nurseAnswer);

        return result;
    }

    @Override
    @Transactional
    public void doctorAnswer(DoctorAnswerDTO doctorAnswerDTO) {
        Long questionId = doctorAnswerDTO.getQuestionId();
        String token = doctorAnswerDTO.getToken();
        String answerText = doctorAnswerDTO.getAnswerText();

        // 验证token
        Integer isValid = messageAlertDAO.validateToken(questionId, token);
        if (isValid == null || isValid == 0) {
            throw new RuntimeException("链接已失效，无法提交作答内容");
        }

        // 更新问题状态
        messageAlertDAO.updateQuestionStatus(questionId);

        // 将当前有效的回答设为无效
        Map<String, Object> activeAnswer = messageAlertDAO.getActiveAnswer(questionId);
        if (activeAnswer != null) {
            Long activeAnswerId = (Long) activeAnswer.get("id");
            messageAlertDAO.updateAnswerStatus(activeAnswerId, false);
        }

        // 插入医生的回答
        messageAlertDAO.insertNurseAnswer(
                questionId,
                0, // source=0表示医生回答
                null, // 医生通过链接回答，不需要name
                answerText,
                true
        );

        // 更新token尝试次数
        messageAlertDAO.updateTokenAttempts(questionId, token);

        // TODO: 发送微信消息通知患者
        // 这里需要实现发送微信客服消息的逻辑
    }
}